package com.wss.lsl.lucene.demo.shipin;

import java.io.File;
import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class IndexUtil {
	public static final Analyzer ANALYZER = new IKAnalyzer();

	private String[] ids = { "1", "2", "3", "4", "5", "6" };
	private String[] emails = { "aa@qq.com", "bb@sina.com", "cc@yahoo.com",
			"dd@chian-rewards.com", "ee@jxt.com", "ff@iaspec.com" };
	private String[] contents = {
			"If you're completely new to the Apache HTTP Server, or even to running a website at all",
			"you might not you know where to start, or what questions to ask.",
			"This document walks you through the basics.",
			"Addresses on the Web are expressed with URLs - Uniform Resource Locators - which specify a protocol (e.g. http)",
			" a servername (e.g. www.apache.org), a URL-path (e.g. /docs/current/getting-started.html), and possibly a query string (e.g. ?arg=value) used to pass additional arguments to the server. ",
			"Details of the transaction, and any error conditions, are written to log files. This is discussed in greater detail below in the Logs Files and Troubleshooting section." };
	private int[] attachs = { 1, 10, 34, 5, 24, 17 };
	private String[] senders = { "weishengshui", "loushulan", "wss", "lsl",
			"zhangsan", "lisi" };
	private Directory directory = null;
	private IndexReader reader = null;

	public IndexUtil() throws IOException {
		directory = FSDirectory.open(new File("d:\\index"));
		reader = IndexReader.open(directory);
	}

	/**
	 * 注意实时更新reader, 不然writer更新索引后，search查询不到最新的数据。
	 * 
	 * @see #getSearcher2()
	 * @return
	 */
	public IndexSearcher getSearcher() {

		return new IndexSearcher(reader);
	}

	/**
	 * 当索引有变化的时候，获取最新的reader
	 * 
	 * @return
	 * @throws IOException
	 */
	public IndexSearcher getSearcher2() throws IOException {

		IndexReader tempReader = IndexReader.openIfChanged(reader);
		if (tempReader != null) { // 索引有更新时，返回的reader不为空，这样能查询到最新的数据
			reader = tempReader;
		}
		return new IndexSearcher(reader);
	}

	/**
	 * 当writer是单列时，每次添加完索引后，writer不会关闭，使用writer.commit();。关闭实际还有一个提交的操作，
	 * 不然添加的document并不能添加进索引，查询不到数据
	 * 
	 * @throws IOException
	 */
	public void index() throws IOException {
		IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35,
				ANALYZER);
		IndexWriter writer = new IndexWriter(directory, config);
		for (int i = 0, lengt = ids.length; i < lengt; i++) {
			Document document = new Document();
			document.add(new Field("id", ids[i], Field.Store.YES,
					Field.Index.NOT_ANALYZED_NO_NORMS));// 存储 不分词
			document.add(new Field("email", emails[i], Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			document.add(new Field("attach", attachs[i] + "", Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			// 添加数字
			document.add(new NumericField("attach", Field.Store.YES, true)
					.setIntValue(attachs[i]));
			// 添加日期也一样，把日期转化为数字
			document.add(new Field("sender", senders[i], Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			document.add(new Field("content", contents[i], Field.Store.NO,
					Field.Index.ANALYZED)); // 存储 分词
			// document.setBoost(10); // 设置加权，排序在前(改变查询结果排序)。默认是1.0f
			// Field.Index.NOT_ANALYZED_NO_NORMS 不分词，不存储评分信息，排序无规则
			// Field.Index.NO 不索引

			writer.addDocument(document);
		}
		writer.commit();

		writer.close();
	}

	public void query(String query) throws CorruptIndexException, IOException,
			ParseException {
		IndexReader reader = IndexReader.open(directory);
		System.out.println("Stored " + reader.numDocs() + " hits.");
		System.out.println("Max score " + reader.maxDoc());
		System.out.println("Number deleted docs " + reader.numDeletedDocs());
		IndexSearcher searcher = new IndexSearcher(reader);
		QueryParser parser = new QueryParser(Version.LUCENE_35, "content",
				ANALYZER);
		Query query2 = parser.parse(query);
		TopDocs docs = searcher.search(query2, 10);
		System.out.println("Found " + docs.totalHits + " hits");
		for (ScoreDoc hit : docs.scoreDocs) {
			Document doc = searcher.doc(hit.doc);
			System.out.println("id: " + doc.get("id") + "\temail: "
					+ doc.get("email"));
		}
		searcher.close();
	}

	public void closeIndex() throws IOException {
		directory.close();
	}

	public void delete() throws CorruptIndexException,
			LockObtainFailedException, IOException {

		IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(
				Version.LUCENE_35, ANALYZER));
		// 删除 id 为 1 的索引，可恢复，使用reader恢复，必须设置reader的只读为false
		writer.deleteDocuments(new Term("id", "1"));
		// 删除全部
		// writer.deleteAll();
		// writer.forceMergeDeletes(); //强制优化，清空回收站
		writer.close();
	}

	/**
	 * 强制删除
	 * 
	 * @throws IOException
	 * @throws LockObtainFailedException
	 * @throws CorruptIndexException
	 */
	public void forceDelete() throws CorruptIndexException,
			LockObtainFailedException, IOException {
		IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(
				Version.LUCENE_35, ANALYZER));
		writer.forceMergeDeletes(); // 强制优化，清空回收站。在3.5之前使用optimize方法，已弃用(消耗资源)
		writer.close();
	}

	public void merege() throws CorruptIndexException,
			LockObtainFailedException, IOException {
		IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(
				Version.LUCENE_35, ANALYZER));

		// 将索引合并为两段
		writer.forceMerge(2);
		writer.close();
	}

	/**
	 * 更新索引：先删除再添加
	 * 
	 * @throws CorruptIndexException
	 * @throws LockObtainFailedException
	 * @throws IOException
	 */
	public void update() throws CorruptIndexException,
			LockObtainFailedException, IOException {
		IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(
				Version.LUCENE_35, ANALYZER));

		/**
		 * lucene 并没有提供更新操作。实际是先删除，再添加
		 */
		Document document = new Document();
		document.add(new Field("id", ids[0], Field.Store.YES,
				Field.Index.NOT_ANALYZED_NO_NORMS));// 存储 不分词
		document.add(new Field("email", emails[0], Field.Store.YES,
				Field.Index.NOT_ANALYZED));
		document.add(new Field("attach", attachs[0] + "", Field.Store.YES,
				Field.Index.NOT_ANALYZED));
		document.add(new Field("sender", senders[0], Field.Store.YES,
				Field.Index.NOT_ANALYZED));
		document.add(new Field("content", contents[0], Field.Store.NO,
				Field.Index.ANALYZED)); // 存储 分词
		// 删除id为1 的文档，再添加 document
		writer.updateDocument(new Term("id", "1"), document);

		writer.close();
	}

	/**
	 * 恢复删除
	 * 
	 * @throws CorruptIndexException
	 * @throws IOException
	 */
	public void unDelete() throws CorruptIndexException, IOException {
		IndexReader reader = IndexReader.open(directory, false);
		reader.undeleteAll();
		reader.close();
	}

	/**
	 * reader 也可以删除
	 * 
	 * @throws CorruptIndexException
	 * @throws IOException
	 */
	public void delete2() throws CorruptIndexException, IOException {
		IndexReader reader = IndexReader.open(directory, false);
		reader.deleteDocuments(new Term("id", "1"));
		reader.close();
	}

	public static void main(String[] args) throws IOException, ParseException {
		IndexUtil indexUtil = new IndexUtil();
		indexUtil.index();
		indexUtil.query("you");
		indexUtil.delete();
		indexUtil.unDelete();
		indexUtil.closeIndex();
	}

}
